package adapletplugin.editors;

import objects.AdapletConstants;
import objects.AdapletConstants.ColumnType;
import objects.Table;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.FormToolkit;

import sections.ISection.Section;
import adapletplugin.dialogs.NewColumnDialog;

public class TableEditor extends AbstractSubEditor
{
	private Text fTableText;
	private Button fNewColumnButton;

	private TableViewer fColumnsTable;
	private TableViewer fStringSizeTable;

	private objects.Table fTableFocus;

	public TableEditor(ScrolledComposite composite, FormToolkit toolkit, MapFileEditor editor)
	{
		super(composite, toolkit, editor);
	}

	@Override
	protected void create()
	{
		Composite row = fToolkit.createComposite(fSubComposite);
		row.setLayout(new GridLayout(2, false));
		row.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

		fToolkit.createLabel(row, "Table Name:");
		fTableText = fToolkit.createText(row, "", SWT.BORDER | SWT.READ_ONLY);
		fTableText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
//		fTableText.addModifyListener(createModifyLister_Name());

		fNewColumnButton = fToolkit.createButton(fSubComposite, "Add Column", SWT.PUSH);
		fNewColumnButton.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false));
		fNewColumnButton.addSelectionListener(createNewColumnSelectListener());

		createColumnsTable();
		createStringSizeTable();
	}

	private void createStringSizeTable()
	{
		int colWidth = AdapletConstants.computeSubWidth(2, 2);
		
		fToolkit.createLabel(fSubComposite, "Sizes of Largestring columns");
		fStringSizeTable = new TableViewer(fSubComposite, SWT.BORDER | SWT.V_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION);
		fStringSizeTable.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		fStringSizeTable.setContentProvider(new StringSizeContentProvider());
		fStringSizeTable.setColumnProperties(new String[] { "Column Name", "String Length" });

		TableViewerColumn viewerColumn = new TableViewerColumn(fStringSizeTable, SWT.NONE);
		TableColumn tabCol = viewerColumn.getColumn();
		tabCol.setText("Column Name");
		tabCol.setMoveable(false);
		tabCol.setWidth(colWidth);
		viewerColumn.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element)
			{
				String sColName = (String) element;
				return sColName;
			}
		});

		viewerColumn = new TableViewerColumn(fStringSizeTable, SWT.NONE);
		tabCol = viewerColumn.getColumn();
		tabCol.setText("String Length");
		tabCol.setMoveable(false);
		tabCol.setWidth(colWidth);
		tabCol.setAlignment(SWT.RIGHT);
		viewerColumn.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element)
			{
				String sColName = (String) element;
				return fTableFocus.getSizeForLargeColumn(sColName);
			}
		});
		viewerColumn.setEditingSupport(new EditingSupport(fStringSizeTable) {

			@Override
			protected void setValue(Object element, Object value)
			{
				String colName = (String) element;
				String newValue = (String) value;

				if (newValue != null && newValue.matches("[0-9]+"))
				{
					fTableFocus.addColumn(colName, ColumnType.LARGESTRING, Integer.parseInt(newValue));
					fEditor.refresh();
					fStringSizeTable.refresh();
					fColumnsTable.refresh();
				}
			}

			@Override
			protected Object getValue(Object element)
			{
				return fTableFocus.getSizeForLargeColumn((String) element);
			}

			@Override
			protected CellEditor getCellEditor(Object element)
			{
				return new TextCellEditor(fStringSizeTable.getTable());
			}

			@Override
			protected boolean canEdit(Object element)
			{
				return true;
			}
		});

		fStringSizeTable.getTable().setHeaderVisible(true);
	}

	private void createColumnsTable()
	{
		int colWidth = AdapletConstants.computeSubWidth(2, 2);
		
		fColumnsTable = new TableViewer(fSubComposite, SWT.BORDER | SWT.V_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION);
		fColumnsTable.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		fColumnsTable.setContentProvider(new ColumnsTableContentProvider());
		fColumnsTable.setColumnProperties(new String[] { "Column Name", "Column Type" });

		TableViewerColumn viewerColumn = new TableViewerColumn(fColumnsTable, SWT.NONE);
		TableColumn tabCol = viewerColumn.getColumn();
		tabCol.setText("Column Name");
		tabCol.setMoveable(false);
		tabCol.setWidth(colWidth);
		viewerColumn.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element)
			{
				String sColName = (String) element;
				return sColName;
			}
		});
		viewerColumn.setEditingSupport(new EditingSupport(fColumnsTable) {

			@Override
			protected void setValue(Object element, Object value)
			{
				String oldColName = (String) element;
				String newColName = (String) value;

				if (newColName == null || newColName.isEmpty())
				{
					return;
				}

				String[] allNames = fTableFocus.getColumnNames();
				for (String curName : allNames)
				{
					if (curName.equals(newColName))
					{
						return;
					}
				}

				ColumnType oldType = fTableFocus.getTypeForColumn(oldColName);
				int colLength = 0;
				if (oldType == ColumnType.LARGESTRING)
				{
					colLength = Integer.parseInt(fTableFocus.getSizeForLargeColumn(oldColName));
				}

				fTableFocus.removeColumn(oldColName);
				fTableFocus.addColumn(newColName, oldType, colLength);

				fColumnsTable.refresh();
				fStringSizeTable.refresh();
				fEditor.refresh();
			}

			@Override
			protected Object getValue(Object element)
			{
				return element;
			}

			@Override
			protected CellEditor getCellEditor(Object element)
			{
				return new TextCellEditor(fColumnsTable.getTable());
			}

			@Override
			protected boolean canEdit(Object element)
			{
				return true;
			}
		});

		viewerColumn = new TableViewerColumn(fColumnsTable, SWT.NONE);
		tabCol = viewerColumn.getColumn();
		tabCol.setText("Column Type");
		tabCol.setMoveable(false);
		tabCol.setWidth(colWidth);
		tabCol.setAlignment(SWT.RIGHT);
		viewerColumn.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element)
			{
				String sColName = (String) element;
				return AdapletConstants.convertTypeToString(fTableFocus.getTypeForColumn(sColName));
			}
		});
		viewerColumn.setEditingSupport(new EditingSupport(fColumnsTable) {

			@Override
			protected void setValue(Object element, Object value)
			{
				String colName = (String) element;
				Integer intVal = (Integer) value;
				
				ColumnType newColType = ColumnType.values()[intVal];

				fTableFocus.removeColumn(colName);
				fTableFocus.addColumn(colName, newColType, 0);
				
				fEditor.refresh();
				fColumnsTable.refresh();
				fStringSizeTable.refresh();
			}

			@Override
			protected Object getValue(Object element)
			{
				String colName = (String) element;
				return fTableFocus.getTypeForColumn(colName).ordinal();
			}

			@Override
			protected CellEditor getCellEditor(Object element)
			{
				String[] items = new String[7];

				items[ColumnType.INT.ordinal()] = AdapletConstants.convertTypeToString(ColumnType.INT);
				items[ColumnType.REAL.ordinal()] = AdapletConstants.convertTypeToString(ColumnType.REAL);
				items[ColumnType.STRING.ordinal()] = AdapletConstants.convertTypeToString(ColumnType.STRING);
				items[ColumnType.DATE.ordinal()] = AdapletConstants.convertTypeToString(ColumnType.DATE);
				items[ColumnType.LONG.ordinal()] = AdapletConstants.convertTypeToString(ColumnType.LONG);
				items[ColumnType.RAW.ordinal()] = AdapletConstants.convertTypeToString(ColumnType.RAW);
				items[ColumnType.LARGESTRING.ordinal()] = AdapletConstants.convertTypeToString(ColumnType.LARGESTRING);

				return new ComboBoxCellEditor(fColumnsTable.getTable(), items, SWT.READ_ONLY);
			}

			@Override
			protected boolean canEdit(Object element)
			{
				return true;
			}
		});

		fColumnsTable.getTable().setHeaderVisible(true);
		createTableContextMenu();
	}

	private void createTableContextMenu()
	{
		Menu menu = new Menu(fColumnsTable.getTable());

		MenuItem item = new MenuItem(menu, SWT.PUSH);
		item.setText("Remove Column");
		item.addSelectionListener(new SelectionAdapter() {

			@Override
			public void widgetSelected(SelectionEvent e)
			{
				IStructuredSelection selection = (IStructuredSelection) fColumnsTable.getSelection();
				String columnName = (String) selection.getFirstElement();

				fTableFocus.removeColumn(columnName);

				fColumnsTable.refresh();
				fStringSizeTable.refresh();
				
				fMap.notifyListeners(Section.TABLE);

				fEditor.refresh();
			}
		});

		fColumnsTable.getTable().setMenu(menu);

	}

	private class StringSizeContentProvider implements IStructuredContentProvider
	{

		@Override
		public void dispose()
		{

		}

		@Override
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
		{

		}

		@Override
		public Object[] getElements(Object inputElement)
		{
			return ((StringSizeTableInput) inputElement).getData();
		}

	}

	private SelectionListener createNewColumnSelectListener()
	{
		return new SelectionAdapter() {

			@Override
			public void widgetSelected(SelectionEvent e)
			{
				Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();

				NewColumnDialog dialog = new NewColumnDialog(shell);

				dialog.create();
				dialog.open();

				if (dialog.getReturnCode() == Window.OK)
				{
					fTableFocus.addColumn(dialog.getColumnName(), dialog.getColumnType(), dialog.getColumnSize());

					fColumnsTable.refresh();
					fStringSizeTable.refresh();
					
					fMap.notifyListeners(Section.TABLE);

					fEditor.refresh();
				}
			}
		};
	}

	private class ColumnsTableContentProvider implements IStructuredContentProvider
	{

		@Override
		public void dispose()
		{

		}

		@Override
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
		{

		}

		@Override
		public Object[] getElements(Object inputElement)
		{
			return ((ColumnTableInput) inputElement).getData();
		}

	}

//	private ModifyListener createModifyLister_Name()
//	{
//		return new ModifyListener() {
//
//			@Override
//			public void modifyText(ModifyEvent e)
//			{
//				if (fTableFocus != null)
//				{
//					fTableFocus.setTableName(fTableText.getText());
//					fMap.notifyListeners(Section.TABLE);
//					fEditor.refresh();
//				}
//			}
//		};
//	}

	@Override
	protected void updateFields()
	{
		fTableFocus = (Table) fFocusObject;

		if (fTableFocus == null)
		{
			fTableText.setText("");
			fColumnsTable.setInput(new ColumnTableInput(null));
			fStringSizeTable.setInput(new StringSizeTableInput(null));
		}
		else
		{
			fTableText.setText(fTableFocus.getTableName());
			fColumnsTable.setInput(new ColumnTableInput(fTableFocus));
			fStringSizeTable.setInput(new StringSizeTableInput(fTableFocus));
		}
	}

	private class ColumnTableInput
	{
		objects.Table fInput;

		public ColumnTableInput(objects.Table inputTable)
		{
			fInput = inputTable;
		}

		public Object[] getData()
		{
			if (fInput == null)
			{
				return new Object[0];
			}

			return fInput.getColumnNames();
		}
	}

	private class StringSizeTableInput
	{
		objects.Table fInput;

		public StringSizeTableInput(objects.Table inputTable)
		{
			fInput = inputTable;
		}

		public Object[] getData()
		{
			if (fInput == null)
			{
				return new Object[0];
			}

			return fInput.getLargeStringColumns();
		}
	}

	@Override
	protected void populateTableComboChoices()
	{
		//Not Needed
	}

	@Override
	protected void populateColumnComboChoices()
	{
		//Not Needed
	}

	@Override
	protected void setColumnNames(String[] columnNames)
	{
		//Not Needed
	}

}
